home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3.2 / Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO / packet / n17jsrc / ec.c < prev    next >
C/C++ Source or Header  |  1991-01-27  |  9KB  |  341 lines

  1. /* Driver for 3COM Ethernet card (PC specific code)
  2.  *
  3.  * This driver is deprecated - use the loadable packet driver from the
  4.  * Clarkson collection instead. Better yet, junk your 3C501 card and buy
  5.  * something more reasonable.
  6.  *
  7.  * Copyright 1991 Phil Karn, KA9Q
  8.  */
  9.  
  10. #define    TIMER    20000    /* Timeout on transmissions */
  11.  
  12. #include <stdio.h>
  13. #include <dos.h>
  14. #include "global.h"
  15. #include "mbuf.h"
  16. #include "enet.h"
  17. #include "iface.h"
  18. #include "pktdrvr.h"
  19. #include "netuser.h"
  20. #include "ec.h"
  21. #include "arp.h"
  22. #include "trace.h"
  23. #include "pc.h"
  24.  
  25. static int ec_init __ARGS((struct iface *iface,unsigned bufsize));
  26. static int ec_raw __ARGS((struct iface *iface,struct mbuf *bp));
  27. static int ec_stop __ARGS((struct iface *iface));
  28. static void getecaddr __ARGS((unsigned base,char *cp));
  29. static void rcv_fixup __ARGS((unsigned base));
  30. static void setecaddr __ARGS((unsigned base,char *cp));
  31.  
  32. static INTERRUPT (*Ecvecsave[EC_MAX])();
  33. static INTERRUPT (*Ecvec[])() = {ec0vec,ec1vec,ec2vec};
  34.  
  35. struct ec Ec[EC_MAX];        /* Per-controller info */
  36. int Nec = 0;
  37.  
  38. /* Initialize interface */
  39. static int
  40. ec_init(iface,bufsize)
  41. struct iface *iface;
  42. unsigned bufsize;    /* Maximum size of receive queue in PACKETS */
  43. {
  44.     register struct ec *ecp;
  45.     register unsigned base;
  46.     int dev;
  47.  
  48.     dev = iface->dev;
  49.     ecp = &Ec[dev];
  50.     base = ecp->base;
  51.     ecp->iface = iface;
  52.  
  53.     /* Pulse IE_RESET */
  54.      outportb(IE_CSR(base),IE_RESET);
  55.  
  56.     /* Save old int vector */
  57.     Ecvecsave[dev] = getirq(ecp->vec);
  58.  
  59.     /* Set interrupt vector */
  60.     if(setirq(ecp->vec,Ecvec[dev]) == -1){
  61.         tprintf("IRQ %u out of range\n",ecp->vec);
  62.         return -1;
  63.     }
  64.     maskon(ecp->vec);    /* Enable interrupt */
  65.     if(iface->hwaddr == NULLCHAR)
  66.         iface->hwaddr = mallocw(EADDR_LEN);
  67.     getecaddr(base,iface->hwaddr);
  68.     setecaddr(base,iface->hwaddr);
  69.     if(memcmp(iface->hwaddr,Ether_bdcst,EADDR_LEN) == 0){
  70.         tprintf("EC address PROM contains broadcast address!!\n");
  71.         return -1;
  72.     }
  73.     /* Enable DMA/interrupt request, gain control of buffer */
  74.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  75.  
  76.     /* Enable transmit interrupts */
  77.     outportb(EDLC_XMT(base),EDLC_16 | EDLC_JAM);
  78.  
  79.     /* Set up the receiver interrupts and flush status */
  80.     outportb(EDLC_RCV(base),EDLC_MULTI|EDLC_GOOD|EDLC_ANY|EDLC_SHORT
  81.      |EDLC_DRIBBLE|EDLC_FCS|EDLC_OVER);
  82.     inportb(EDLC_RCV(base));
  83.  
  84.     /* Start receiver */
  85.     outportw(IE_RP(base),0);    /* Reset read pointer */
  86.     outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  87.     return 0;
  88. }
  89. /* Send raw packet (caller provides header) */
  90. static int
  91. ec_raw(iface,bp)
  92. struct iface *iface;    /* Pointer to interface control block */
  93. struct mbuf *bp;        /* Data field */
  94. {
  95.     register struct ec *ecp;
  96.     register unsigned base;
  97.     register int i;
  98.     short size;
  99.  
  100.     dump(iface,IF_TRACE_OUT,CL_ETHERNET,bp);
  101.     iface->rawsndcnt++;
  102.     iface->lastsent = secclock();
  103.  
  104.     ecp = &Ec[iface->dev];
  105.     base = ecp->base;
  106.  
  107.     ecp->estats.xmit++;
  108.  
  109.     size = len_p(bp);
  110.     /* Pad the size out to the minimum, if necessary,
  111.      * with junk from the last packet (nice security hole here)
  112.      */
  113.     if(size < RUNT)
  114.         size = RUNT;
  115.     size = (size+1) & ~1;    /* round size up to next even number */
  116.  
  117.     /* Wait for transmitter ready, if necessary. IE_XMTBSY is valid
  118.      * only in the transmit mode, hence the initial check.
  119.      */
  120.     if((inportb(IE_CSR(base)) & IE_BUFCTL) == IE_XMTEDLC){
  121.         for(i=TIMER;(inportb(IE_CSR(base)) & IE_XMTBSY) && i != 0;i--)
  122.             ;
  123.         if(i == 0){
  124.             ecp->estats.timeout++;
  125.             free_p(bp);
  126.             return -1;
  127.         }
  128.     }
  129.     ecp->size = size;
  130.     /* Get control of the board buffer and disable receiver */
  131.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  132.     /* Point GP at beginning of packet */
  133.     outportw(IE_GP(base),BFRSIZ-size);
  134.     /* Actually load each piece with a fast assembler routine */
  135.     while(bp != NULLBUF){
  136.         outbuf(IE_BFR(base),bp->data,bp->cnt);
  137.         bp = free_mbuf(bp);
  138.     }
  139.     /* Start transmitter */
  140.     outportw(IE_GP(base),BFRSIZ-size);
  141.     outportb(IE_CSR(base),IE_RIDE|IE_XMTEDLC);
  142.     return 0;
  143. }
  144. /* Ethernet interrupt handler */
  145. void
  146. ecint(dev)
  147. int dev;
  148. {
  149.     register struct ec *ecp;
  150.     register unsigned base;
  151.     struct mbuf *bp;
  152.     int16 size;
  153.     char stat;
  154.     struct phdr phdr;
  155.  
  156.     ecp = &Ec[dev];
  157.     base = Ec[dev].base;
  158.     ecp->estats.intrpt++;
  159.  
  160.     /* Check for transmit jam */
  161.     if(!(inportb(IE_CSR(base)) & IE_XMTBSY)){
  162.         stat = inportb(EDLC_XMT(base));
  163.         if(stat & EDLC_16){
  164.             ecp->estats.jam16++;
  165.             rcv_fixup(base);
  166.         } else if(stat & EDLC_JAM){
  167.             /* Crank counter back to beginning and restart transmit */
  168.             ecp->estats.jam++;
  169.             outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  170.             outportw(IE_GP(base),BFRSIZ - ecp->size);
  171.             outportb(IE_CSR(base),IE_RIDE|IE_XMTEDLC);
  172.         }
  173.     }
  174.     for(;;){
  175.         stat = inportb(EDLC_RCV(base));
  176.         if(stat & EDLC_STALE)
  177.             break;
  178.  
  179.         if(stat & EDLC_OVER){
  180.             ecp->estats.over++;
  181.             rcv_fixup(base);
  182.             continue;
  183.         }
  184.         if(stat & (EDLC_SHORT | EDLC_FCS | EDLC_DRIBBLE)){
  185.             ecp->estats.bad++;
  186.             rcv_fixup(base);
  187.             continue;
  188.         }
  189.         if(stat & EDLC_ANY){
  190.             /* Get control of the buffer */
  191.             outportw(IE_GP(base),0);
  192.             outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  193.         
  194.             /* Allocate mbuf and copy the packet into it */
  195.             size = inportw(IE_RP(base));
  196.             if(size < RUNT || size > GIANT)
  197.                 ecp->estats.bad++;
  198.             else if((bp = alloc_mbuf(size+sizeof(phdr))) == NULLBUF)
  199.                 ecp->estats.nomem++;
  200.             else {
  201.                 ecp->estats.recv++;
  202.                 /* Generate descriptor header */
  203.                 phdr.iface = ecp->iface;
  204.                 phdr.type = CL_ETHERNET;
  205.                 memcpy(&bp->data[0],(char *)&phdr,sizeof(phdr));
  206.                 inbuf(IE_BFR(base),bp->data+sizeof(phdr),size);
  207.                 bp->cnt = size + sizeof(phdr);
  208.                 enqueue(&Hopper,bp);
  209.             }
  210.             outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  211.             outportb(IE_RP(base),0);
  212.         }
  213.     }
  214.     /* Clear any spurious interrupts */
  215.     (void)inportb(EDLC_RCV(base));
  216.     (void)inportb(EDLC_XMT(base));
  217. }
  218. static void
  219. rcv_fixup(base)
  220. register unsigned base;
  221. {
  222.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  223.     outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  224.     outportb(IE_RP(base),0);
  225. }
  226. /* Read Ethernet address from controller PROM */
  227. static void
  228. getecaddr(base,cp)
  229. register unsigned base;
  230. register char *cp;
  231. {
  232.     register int i;
  233.  
  234.     for(i=0;i<EADDR_LEN;i++){
  235.         outportw(IE_GP(base),i);
  236.         *cp++ = inportb(IE_SAPROM(base));
  237.     }
  238. }
  239. /* Set Ethernet address on controller */
  240. static void
  241. setecaddr(base,cp)
  242. register unsigned base;
  243. register char *cp;
  244. {
  245.     register int i;
  246.  
  247.     for(i=0;i<EADDR_LEN;i++)
  248.         outportb(EDLC_ADDR(base)+i,*cp++);
  249. }
  250. /* Shut down the Ethernet controller */
  251. static int
  252. ec_stop(iface)
  253. struct iface *iface;
  254. {
  255.     register unsigned base;
  256.     int dev;
  257.     register struct ec *ecp;
  258.  
  259.     dev = iface->dev;
  260.     ecp = &Ec[dev];
  261.     base = ecp->base;
  262.  
  263.     /* Disable interrupt */
  264.     maskoff(Ec[dev].vec);
  265.  
  266.     /* Restore original interrupt vector */
  267.     setirq(ecp->vec,Ecvecsave[dev]);
  268.  
  269.     /* Pulse IE_RESET */
  270.     outportb(IE_CSR(base),IE_RESET);
  271.     outportb(IE_CSR(base),0);
  272.     return 0;
  273. }
  274. /* Attach a 3-Com model 3C500 Ethernet controller to the system
  275.  * argv[0]: hardware type, must be "3c500"
  276.  * argv[1]: I/O address, e.g., "0x300"
  277.  * argv[2]: vector, e.g., "3"
  278.  * argv[3]: mode, must be "arpa"
  279.  * argv[4]: interface label, e.g., "ec0"
  280.  * argv[5]: maximum number of packets allowed on receive queue, e.g., "5"
  281.  * argv[6]: maximum transmission unit, bytes, e.g., "1500"
  282.  * argv[7]: IP address, optional (defaults to Ip_addr)
  283.  */
  284. int
  285. ec_attach(argc,argv,p)
  286. int argc;
  287. char *argv[];
  288. void *p;
  289. {
  290.     register struct iface *if_ec;
  291.     int dev;
  292.  
  293.     if(Nec >= EC_MAX){
  294.         tprintf("Too many Ethernet controllers\n");
  295.         return -1;
  296.     }
  297.     if(if_lookup(argv[4]) != NULLIF){
  298.         tprintf("Interface %s already exists\n",argv[4]);
  299.         return -1;
  300.     }
  301.     dev = Nec++;
  302.     if_ec = (struct iface *)callocw(1,sizeof(struct iface));
  303.     if_ec->addr = Ip_addr;
  304.     if(argc > 7)
  305.         if_ec->addr = resolve(argv[7]);
  306.     if(if_ec->addr == 0){
  307.         tprintf(Noipaddr);
  308.         free((char *)if_ec);
  309.         return -1;
  310.     }
  311.     if_ec->name = strdup(argv[4]);
  312.     if_ec->mtu = atoi(argv[6]);
  313.     if_ec->type = CL_ETHERNET;
  314.     if_ec->send = enet_send;
  315.     if_ec->output = enet_output;
  316.     if_ec->raw = ec_raw;
  317.     if_ec->stop = ec_stop;
  318.     if_ec->dev = dev;
  319.  
  320.     Ec[dev].base = htoi(argv[1]);
  321.     Ec[dev].vec = htoi(argv[2]);
  322.  
  323.     if(strcmp(argv[3],"arpa") != 0){
  324.         tprintf("Mode %s unknown for interface %s\n",
  325.             argv[3],argv[4]);
  326.         free(if_ec->name);
  327.         free((char *)if_ec);
  328.         return -1;
  329.     }
  330.     /* Initialize device */
  331.     if(ec_init(if_ec,(unsigned)atoi(argv[5])) != 0){
  332.         free(if_ec->name);
  333.         free((char *)if_ec);
  334.         return -1;
  335.     }
  336.     if_ec->next = Ifaces;
  337.     Ifaces = if_ec;
  338.  
  339.     return 0;
  340. }
  341.